/*
 * 光电传感器防误触发滤波示例
 * 
 * 本示例展示如何使用FXEtherCAT SDK的回调功能结合滤波器
 * 来处理光电传感器的误触发问题，提高信号的稳定性和可靠性。
 */

using System;
using System.Threading;
using System.Threading.Tasks;
using FXEtherCAT.SDK;

namespace PhotoelectricFilterExample
{
    class Program
    {
        private static FXEtherCATSDK? _sdk;
        private static bool _isRunning = true;
        private static int _validDetectionCount = 0;
        private static int _totalEventCount = 0;
        private static readonly object _lockObj = new object();

        // 光电传感器配置
        private const ushort SLAVE_NUMBER = 0;
        private const ushort PHOTOELECTRIC_INDEX = 0x6000;
        private const byte PHOTOELECTRIC_SUBINDEX = 1;

        static async Task Main(string[] args)
        {
            Console.WriteLine("=== 光电传感器防误触发滤波示例 ===");
            Console.WriteLine("本示例演示如何使用回调+滤波器处理光电传感器误触发");
            Console.WriteLine();

            try
            {
                // 初始化SDK
                _sdk = new FXEtherCATSDK();
                Console.WriteLine("✓ SDK初始化成功");

                // 配置光电传感器防抖滤波器
                ConfigurePhotoelectricFilter();

                // 注册回调事件
                RegisterCallbackEvents();

                // 启动数据监控
                if (_sdk.StartReadDataMonitoring())
                {
                    Console.WriteLine("✓ 数据监控已启动，等待光电传感器信号...");
                    Console.WriteLine();
                    
                    // 显示使用说明
                    ShowUsageInstructions();

                    // 启动状态监控任务
                    var statusTask = MonitorSystemStatus();

                    // 等待用户输入退出
                    Console.WriteLine("按 'q' 键退出程序...");
                    while (_isRunning)
                    {
                        var key = Console.ReadKey(true);
                        if (key.KeyChar == 'q' || key.KeyChar == 'Q')
                        {
                            _isRunning = false;
                            break;
                        }
                        else if (key.KeyChar == 's' || key.KeyChar == 'S')
                        {
                            ShowFilterStatus();
                        }
                        else if (key.KeyChar == 'r' || key.KeyChar == 'R')
                        {
                            ResetCounters();
                        }
                    }

                    await statusTask;
                }
                else
                {
                    Console.WriteLine("❌ 启动数据监控失败");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"❌ 程序异常: {ex.Message}");
                Console.WriteLine($"详细信息: {ex}");
            }
            finally
            {
                // 清理资源
                _sdk?.StopReadDataMonitoring();
                _sdk?.Dispose();
                Console.WriteLine("✓ 资源已清理");
            }

            Console.WriteLine("\n程序已退出，按任意键关闭...");
            Console.ReadKey();
        }

        /// <summary>
        /// 配置光电传感器防抖滤波器
        /// </summary>
        private static void ConfigurePhotoelectricFilter()
        {
            Console.WriteLine("--- 配置光电传感器滤波器 ---");

            // 滑动窗口滤波（抗干扰光电传感器滤波）：
            // 使用 WindowSizeMs 作为滑动窗口大小（50ms = 50个1ms采样）
            // 使用 RisingThreshold/FallingThreshold 控制滞回阈值
            var slidingWindowFilter = new ReadDataFilter
            {
                Type = FilterType.SlidingWindow,
                WindowSizeMs = 50,          // 滑动窗口大小 50ms
                RisingThreshold = 40,       // 上升阈值：50个采样中至少40个为1才输出1
                FallingThreshold = 30,      // 下降阈值：50个采样中少于30个为1才输出0
                MonitoredBits = { },        // 空列表：监控整个值
                Logic = BitLogic.Any,       // 位逻辑：任意位
                EdgeType = EdgeType.Both    // 检测进入和离开
            };

            bool result = _sdk!.ConfigureReadDataFilter(SLAVE_NUMBER, PHOTOELECTRIC_INDEX, PHOTOELECTRIC_SUBINDEX, slidingWindowFilter);

            if (result)
            {
                Console.WriteLine($"✓ 光电传感器滑动窗口滤波配置成功");
                Console.WriteLine($"  - 从站: {SLAVE_NUMBER}");
                Console.WriteLine($"  - 地址: 0x{PHOTOELECTRIC_INDEX:X4}:{PHOTOELECTRIC_SUBINDEX}");
                Console.WriteLine($"  - 最小物体持续: {enhancedDebounceFilter.DebounceTimeMs}ms");
                Console.WriteLine($"  - 最大允许间隙: {enhancedDebounceFilter.TimeWindowMs}ms (0=传统防抖)");
            }
            else
            {
                Console.WriteLine("❌ 光电传感器滤波器配置失败");
            }
            
            Console.WriteLine();
        }

        /// <summary>
        /// 注册回调事件
        /// </summary>
        private static void RegisterCallbackEvents()
        {
            Console.WriteLine("--- 注册回调事件 ---");

            _sdk!.SlaveReadDataChanged += OnPhotoelectricDataChanged;
            Console.WriteLine("✓ 光电传感器数据变化回调已注册");
            Console.WriteLine();
        }

        /// <summary>
        /// 光电传感器数据变化回调处理
        /// </summary>
        private static void OnPhotoelectricDataChanged(object? sender, SlaveReadDataChangedEventArgs e)
        {
            lock (_lockObj)
            {
                _totalEventCount++;

                // 只处理我们关心的光电传感器
                if (e.SlaveNumber == SLAVE_NUMBER && 
                    e.Index == PHOTOELECTRIC_INDEX && 
                    e.Subindex == PHOTOELECTRIC_SUBINDEX)
                {
                    _validDetectionCount++;
                    
                    // 判断是物体进入还是离开
                    string action = e.NewValue == 1 ? "物体进入" : "物体离开";
                    string status = e.NewValue == 1 ? "🔴 检测到" : "🟢 清空";
                    
                    Console.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] {status} {action}");
                    Console.WriteLine($"  └─ 从站{e.SlaveNumber}, 值={e.NewValue}, 时间戳={e.TimestampUs}μs");
                    
                    // 这里可以添加您的业务逻辑
                    HandlePhotoelectricDetection(e.NewValue == 1, e.TimestampUs);
                }
            }
        }

        /// <summary>
        /// 处理光电传感器检测逻辑
        /// </summary>
        private static void HandlePhotoelectricDetection(bool objectDetected, ulong timestampUs)
        {
            if (objectDetected)
            {
                // 物体进入检测区域
                Console.WriteLine("  ➤ 执行动作: 物体检测处理");
                
                // 在这里添加您的业务逻辑，例如：
                // - 停止传送带
                // - 触发拍照
                // - 记录通过时间
                // - 发送信号给其他设备
                
                // 示例：模拟一些处理
                // StopConveyor();
                // TriggerCamera();
                // LogDetectionEvent(timestampUs);
            }
            else
            {
                // 物体离开检测区域
                Console.WriteLine("  ➤ 执行动作: 物体离开处理");
                
                // 在这里添加您的业务逻辑，例如：
                // - 重启传送带
                // - 重置检测状态
                // - 计算通过时间
                
                // 示例：模拟一些处理
                // StartConveyor();
                // ResetDetectionState();
            }
        }

        /// <summary>
        /// 显示使用说明
        /// </summary>
        private static void ShowUsageInstructions()
        {
            Console.WriteLine("=== 使用说明 ===");
            Console.WriteLine("• 程序正在监控光电传感器信号");
            Console.WriteLine("• 已配置50ms防抖滤波器，消除误触发");
            Console.WriteLine("• 支持物体进入/离开双向检测");
            Console.WriteLine();
            Console.WriteLine("快捷键:");
            Console.WriteLine("  's' - 显示滤波器状态");
            Console.WriteLine("  'r' - 重置计数器");
            Console.WriteLine("  'q' - 退出程序");
            Console.WriteLine();
            Console.WriteLine("=== 实时监控 ===");
        }

        /// <summary>
        /// 显示滤波器状态
        /// </summary>
        private static void ShowFilterStatus()
        {
            Console.WriteLine("\n--- 滤波器状态 ---");
            
            var status = _sdk!.GetFilterStatus(SLAVE_NUMBER, PHOTOELECTRIC_INDEX, PHOTOELECTRIC_SUBINDEX);
            if (status != null)
            {
                Console.WriteLine($"滤波器状态: {(status.IsActive ? "激活" : "未激活")}");
                Console.WriteLine($"通过事件数: {status.PassedEventCount}");
                Console.WriteLine($"滤波事件数: {status.FilteredEventCount}");
                Console.WriteLine($"最后事件时间: {status.LastEventTime:HH:mm:ss.fff}");
                
                if (status.FilteredEventCount > 0)
                {
                    double filterEfficiency = (double)status.FilteredEventCount / (status.PassedEventCount + status.FilteredEventCount) * 100;
                    Console.WriteLine($"滤波效率: {filterEfficiency:F1}% (滤掉了 {status.FilteredEventCount} 次误触发)");
                }
            }
            else
            {
                Console.WriteLine("❌ 无法获取滤波器状态");
            }
            Console.WriteLine();
        }

        /// <summary>
        /// 重置计数器
        /// </summary>
        private static void ResetCounters()
        {
            lock (_lockObj)
            {
                _validDetectionCount = 0;
                _totalEventCount = 0;
            }
            Console.WriteLine("\n✓ 计数器已重置\n");
        }

        /// <summary>
        /// 监控系统状态
        /// </summary>
        private static async Task MonitorSystemStatus()
        {
            var lastPrintTime = DateTime.Now;
            
            while (_isRunning)
            {
                await Task.Delay(5000); // 每5秒显示一次状态
                
                if (_isRunning && DateTime.Now - lastPrintTime > TimeSpan.FromSeconds(5))
                {
                    lock (_lockObj)
                    {
                        if (_totalEventCount > 0 || _validDetectionCount > 0)
                        {
                            Console.WriteLine($"\n--- 状态统计 (运行时间: {DateTime.Now - lastPrintTime:mm\\:ss}) ---");
                            Console.WriteLine($"有效检测次数: {_validDetectionCount}");
                            Console.WriteLine($"总事件次数: {_totalEventCount}");
                            Console.WriteLine("提示: 按 's' 查看详细滤波器状态\n");
                        }
                    }
                    lastPrintTime = DateTime.Now;
                }
            }
        }
    }
}
